package belf.migrate.core.util;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.SignStyle;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import static java.time.temporal.ChronoField.*;

public class DateUtils {
    private static final Map<Formatter, DateTimeFormatter> FORMATTER_MAP = new HashMap<>();

    public static final Pattern[] PATTERN_ARRAY =
            new Pattern[]{
                    Pattern.compile("\\d{8}"),
                    Pattern.compile("\\d{4}-\\d{2}-\\d{2}"),
                    Pattern.compile("\\d{4}\\.\\d{2}\\.\\d{2}"),
                    Pattern.compile("\\d{4}/\\d{2}/\\d{2}"),
                    Pattern.compile("\\d{4}年\\d{2}月\\d{2}日")
            };

    public static final Map<Pattern, DateTimeFormatter> DATE_FORMATTER_MAP = new HashMap();

    static {
        DATE_FORMATTER_MAP.put(
                PATTERN_ARRAY[0],
                DateTimeFormatter.ofPattern(Formatter.YYYYMMDD.value));

        DATE_FORMATTER_MAP.put(
                PATTERN_ARRAY[1],
                DateTimeFormatter.ofPattern(Formatter.YYYY_MM_DD.value));

        DATE_FORMATTER_MAP.put(
                PATTERN_ARRAY[2],
                DateTimeFormatter.ofPattern(Formatter.YYYY_MM_DD_SPOT.value));

        DATE_FORMATTER_MAP.put(
                PATTERN_ARRAY[3],
                DateTimeFormatter.ofPattern(Formatter.YYYY_MM_DD_SLASH.value));

        DATE_FORMATTER_MAP.put(
                PATTERN_ARRAY[4],
                DateTimeFormatter.ofPattern(Formatter.ChinaDate.value));
    }

    /**
     * gave a date string and return the {@link DateTimeFormatter} which can be used to parse it.
     *
     * @param dateTime eg: 2020-02-03
     * @return the DateTimeFormatter matched, will return null when not matched any pattern in
     *     {@link #PATTERN_ARRAY}
     */
    public static DateTimeFormatter matchDateFormatter(String dateTime) {
        for (int j = 0; j < PATTERN_ARRAY.length; j++) {
            if (PATTERN_ARRAY[j].matcher(dateTime).matches()) {
                return DATE_FORMATTER_MAP.get(PATTERN_ARRAY[j]);
            }
        }
        return null;
    }

    public static LocalDate parse(String date) {
        DateTimeFormatter dateTimeFormatter = matchDateFormatter(date);
        return parse(date, dateTimeFormatter);
    }

    public static LocalDate parse(String date, DateTimeFormatter dateTimeFormatter) {
        return LocalDate.parse(date, dateTimeFormatter);
    }

    public static LocalDate parse(String date, Formatter formatter) {
        return LocalDate.parse(date, FORMATTER_MAP.get(formatter));
    }

    public static String toString(LocalDate date, Formatter formatter) {
        return date.format(FORMATTER_MAP.get(formatter));
    }

    public enum Formatter {
        YYYYMMDD("yyyyMMdd"),
        YYYY_MM_DD("yyyy-MM-dd"),
        YYYY_MM_DD_SPOT("yyyy.MM.dd"),
        YYYY_MM_DD_SLASH("yyyy/MM/dd"),
        ChinaDate("yyyy年MM月dd日");

        private final String value;

        Formatter(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public static Formatter parse(String format) {
            Formatter[] formatters = Formatter.values();
            for (Formatter formatter : formatters) {
                if (formatter.getValue().equals(format)) {
                    return formatter;
                }
            }
            String errorMsg = String.format("Illegal format [%s]", format);
            throw new IllegalArgumentException(errorMsg);
        }
    }
}
